﻿using System;
using System.Diagnostics;
using System.Threading;
using log4net;
using SystemCounter = System.Diagnostics.PerformanceCounter;

namespace Jiubang.Communication.Server.DataTransport
{
    internal sealed class PerformanceCounter : IDisposable
    {
        #region Private Fields

        private const string CategoryName = "Jiubang.Communication";
        private readonly Timer _timer;
        private readonly ILog _log;

        private long _totalAccepted;
        private long _totalClosed;
        private long _totalSent;
        private long _totalReceived;
        private long _totalSentBytes;
        private long _totalReceivedBytes;

        private long _previousSecondAccepted;
        private long _previousSecondClosed;
        private long _previousSecondSent;
        private long _previousSecondReceived;
        private long _previousSecondSentBytes;
        private long _previousSecondreceivedBytes;

        //系统运行的总秒数
        private static SystemCounter _upTimeCounter;

        //每秒发送的字节数
        private static SystemCounter _sendCounter;

        //系统接受的Socket总数
        private static SystemCounter _acceptedCounter;

        //每秒接收的字节数
        private static SystemCounter _receiveCounter;

        //系统关闭的Socket总数
        private static SystemCounter _closeCounter;

        //发送消息的总次数
        private static SystemCounter _sendByteCounter;

        //接收消息的总次数
        private static SystemCounter _receiveByteCounter; 

        #endregion

        static PerformanceCounter()
        {
            SetupCategory();
            CreateCounters();
        }

        private static void CreateCounters()
        {
            _upTimeCounter = new SystemCounter(CategoryName, "uptime", false);
            _acceptedCounter = new SystemCounter(CategoryName, "accepted", false);
            _closeCounter = new SystemCounter(CategoryName, "closed", false);
            _sendCounter = new SystemCounter(CategoryName, "sent", false);
            _receiveCounter = new SystemCounter(CategoryName, "received", false);
            _sendByteCounter = new SystemCounter(CategoryName, "sentBytes / sec", false);
           _receiveByteCounter = new SystemCounter(CategoryName, "receivedBytes / sec", false);
        }

        public PerformanceCounter(string name)
        {
            _log = LogManager.GetLogger(GetType());

            _timer = new Timer(o =>
            {
                try
                {
                    Increment(_totalAccepted, ref _previousSecondAccepted, _acceptedCounter);
                    Increment(_totalSent, ref _previousSecondSent, _sendCounter);
                    Increment(_totalSentBytes, ref _previousSecondSentBytes, _sendByteCounter);
                    Increment(_totalReceived, ref _previousSecondReceived, _receiveCounter);
                    Increment(_totalReceivedBytes, ref _previousSecondreceivedBytes, _receiveByteCounter);
                    Increment(_totalClosed, ref _previousSecondClosed, _closeCounter);
                    
                    _upTimeCounter.Increment();

                }
                catch (Exception e)
                {
                    _log.Error(e);
                }

            }, null, 1000, 1000);
        }

        private static void Increment(long totoalValue, ref long previousSencendValue, SystemCounter counter)
        {
            var newCount = totoalValue - previousSencendValue;
            Interlocked.Add(ref previousSencendValue, newCount);

            counter.IncrementBy(newCount);
        }

        private static void SetupCategory()
        {
            if (PerformanceCounterCategory.Exists(CategoryName)) return;

            var collection = new CounterCreationDataCollection
                                 {
                                     new CounterCreationData("uptime", "系统运行的总秒数",
                                                             PerformanceCounterType.ElapsedTime),
                                     new CounterCreationData("accepted", "系统接受的Socket总数",
                                                             PerformanceCounterType.NumberOfItems32),
                                     new CounterCreationData("closed", "系统关闭的Socket总数",
                                                             PerformanceCounterType.NumberOfItems32),
                                     new CounterCreationData("sent", "发送消息的总次数",
                                                             PerformanceCounterType.NumberOfItems32),
                                     new CounterCreationData("received", "接收消息的总次数",
                                                             PerformanceCounterType.NumberOfItems32),                                                               
                                     new CounterCreationData("sentBytes / sec", "每秒发送的字节数",
                                                             PerformanceCounterType.RateOfCountsPerSecond32),
                                     new CounterCreationData("receivedBytes / sec", "每秒接收的字节数",
                                                             PerformanceCounterType.RateOfCountsPerSecond32)
                                 };

            PerformanceCounterCategory.Create(CategoryName, "Jiubang.Communication框架性能计数器",
                                              PerformanceCounterCategoryType.MultiInstance, collection);
        }

        public void Send(int bytes)
        {
            if (bytes <= 0)
                throw new ArgumentOutOfRangeException("bytes");

            Interlocked.Increment(ref _totalSent);
            Interlocked.Add(ref _totalSentBytes, bytes);
        }

        public void Receive(int bytes)
        {
            if (bytes <= 0)
                throw new ArgumentOutOfRangeException("bytes");

            Interlocked.Increment(ref _totalReceived);
            Interlocked.Add(ref _totalReceivedBytes, bytes);
        }

        public void Accept()
        {
            Interlocked.Increment(ref _totalAccepted);
        }

        public void Close()
        {
            Interlocked.Increment(ref _totalClosed);
        }

        public void Dispose()
        {
            _timer.Dispose();
        }
    }
}
